#include "Camera.h"

Camera::Camera(const glm::vec2 & center,
			float spanW,
			float spanH,
			float pixToMeterRatio)
{
	mCenter = center;
	mWh[0] = spanW;
	mWh[1] = spanH;

	mFollowObj = NULL;

	mMVMat = glm::mat4(1.0);
	mPMat = glm::mat4(1.0);

	mEnableFollow = false;

	SetPerspectiveMatrix(0, spanW, 0, spanH);
	SetModelviewMatrix(pixToMeterRatio);
}

void Camera::SetPerspectiveMatrix(
	float left,
	float right,
	float bottom,
	float top)
{
		//gluOrtho2D - znear = -1, zfar = 1
		float wh = (right-left)/2;
		float hh = (top - bottom)/2;
		mPMat = glm::ortho(left-wh, right-wh, bottom-hh, top-hh);
}

void Camera::SetPixelToMeterRatio( float inRat ) {
	SetModelviewMatrix(inRat);
}

void Camera::IncrementPixelToMeterRatio (float inc) {
	SetModelviewMatrix(mPixelPerMeter + inc);
}

void Camera::SetModelviewMatrix()
{
	SetModelviewMatrix(mPixelPerMeter);
}

void Camera::SetModelviewMatrix(float pixtometer)
{	
	mPixelPerMeter = pixtometer;
	if (mPixelPerMeter < 1) {
		mPixelPerMeter = 1;
	}
	glm::vec2 pos = glm::vec2(mCenter.x, mCenter.y);
	glm::vec3 eye = glm::vec3(pos, 1);
	glm::vec3 cent = glm::vec3(pos, 0);

	glm::mat4x4 lookat = glm::lookAt( eye,
									  cent,
									  glm::vec3(0.0, 1.0, 0.0) );
	
	mMVMat = glm::scale(lookat, glm::vec3(mPixelPerMeter));
}

glm::mat4x4 * Camera::GetGLMMat(CAMERA_GET_ENUM flag){
	switch(flag)
	{
		case MODELVIEW_MATRIX:
			return &mMVMat;
			break;
		case PROJECTION_MATRIX:
			return &mPMat;
			break;
		default:
			return NULL;
			break;
	};

	return NULL;
}

float * Camera::GetFloat (CAMERA_GET_ENUM flag)
{
	glm::mat4x4 * mat = GetGLMMat(flag);
	
	if (mat != NULL) {
		return &(*mat)[0][0];
	}

	return NULL;
}

void Camera::SetFollow(PhysicsPrimitive * inPrim)
{
	this->mFollowObj = inPrim;
}

void Camera::SetDoFollow( bool doFollow )
{
	mEnableFollow = doFollow;
}

void Camera::Update()
{
	if (!mEnableFollow || mFollowObj == NULL) {
		return;
	}

	b2Vec2 cent = mFollowObj->mBody->GetWorldCenter();
	MoveTo(glm::vec2(cent.x, cent.y));

}

bool Camera::IsFollowing()
{
	if (mEnableFollow && mFollowObj) {
		return true;
	}

	return false;
}

void Camera::GetMinMax( glm::vec2 & oMin, glm::vec2 & oMax ) {
	glm::vec2 whWorldHalf = glm::vec2((mWh[0]*0.5)/mPixelPerMeter, (mWh[1]*0.5)/mPixelPerMeter);
	oMin = glm::vec2( mCenter.x - whWorldHalf.x,
					 mCenter.y - whWorldHalf.y);
	oMax = glm::vec2( mCenter.x + whWorldHalf.x,
					  mCenter.y +  whWorldHalf.y);
}

//Moves camera to a world position
void Camera::MoveTo( const glm::vec2 & worldPos )
{
	SetPosAsFarAsPossible( worldPos );
}

//Moves the camera by incrementing its current position.
void Camera::MoveByDelta( const glm::vec2 & amt )
{
	SetPosAsFarAsPossible( glm::vec2( mCenter.x + amt.x, mCenter.y + amt.y ) );
}

//DON'T USE THESE. ONLY USE MoveTo and MoveByDelta functions.
void Camera::SetPosAsFarAsPossible( const glm::vec2 & pos ) {
	SetCenter(pos);
}

void Camera::SetCenter(const glm::vec2 & cent ){
	mCenter = cent;
	SetModelviewMatrix();
}